#include "FileStream.h"
#include <iostream>

#include "File.h"

namespace streamdb {

FileStream::FileStream(const std::string & fname) 
: file(std::unique_ptr<File>(new File(fname)))
, size(0)
, isOpen(false)
{
}

FileStream::~FileStream() {
    close();
}

void FileStream::close(){
    if(isOpen){
        file->close();
        isOpen = false;
    }
}

Status FileStream::open(){
    if(isOpen == false){
        file->openRW();
        file->getSize(size);
        isOpen = true;
    }
    return Status::OK();
}
const std::string & FileStream::getName() const {
    return file->getFileName();
}
Status FileStream::append(const std::string & obj) {
    if(!isOpen){
        std::cout << "not open" << std::endl;
        return Status::InvalidArgument();
    }

    if(!obj.empty()){
        //TODO: std::cout << "FileStream save the msg:" << obj << std::endl;

        //TODO: write sucess  Refactor to Batch write
        //1. write length
        auto s = file->writeUint64(obj.size());
        if(!s.isOk()){
            return s;
        }
        size += sizeof(uint64_t);

        //2. write content
        uint64_t cap = obj.size();
        s = file->write(obj.c_str(), cap);
        if(!s.isOk()){
            return s;
        }
        size += cap;
    }
    else{
        std::cout << "message is null, don't save it:" << obj << std::endl;
    }
    return Status::OK();
}


bool FileStream::iterator::hasNext() const {
    auto s = file.readUint64(size);
    if(s.isOk()){
        return true;
    }
    if(s.isEndOfFile()){
        return false;
    }
    std::cout << s.toString() << std::endl;
    return false;
}
std::string & FileStream::iterator::next() {
    auto s = file.read(buf, size);
    if(s.isOk()){
        value.assign(buf, size);
    }
    else
        value.clear();
    return value;
}

std::shared_ptr<SequenceStream<std::string>::IteratorType> 
FileStream::advance(int64_t offset) {
    auto s = file->seekOffset(offset);
    if(s.isOk()){
        std::cout << "offset:" <<offset  << " size:" << getSize() << std::endl;
        return std::shared_ptr<SequenceStream<std::string>::IteratorType>(new iterator(*file));
    }
    return std::shared_ptr<SequenceStream<std::string>::IteratorType>();
}

std::shared_ptr<SequenceStream<std::string>::IteratorType> 
FileStream::begin() {
    auto s = file->seekBegin();
    if(s.isOk()){
        return std::shared_ptr<SequenceStream<std::string>::IteratorType>(new iterator(*file));
    }
    return std::shared_ptr<SequenceStream<std::string>::IteratorType>();
}

}//namespace streamdb
